﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;

namespace efuture.xml
{

    public interface IControlIterator
    {
        void handle(Control c);

    }

    public class BindingControlIterator : IControlIterator
    {
        private XPathDocument xDoc;
        private XPathNavigator xNav;
        private String XPath;

        public BindingControlIterator(XPathDocument xDoc, XPathNavigator xNav, String XPath)
        {
            this.xDoc = xDoc;
            this.xNav = xNav;
            this.XPath = XPath;
        }

        public void handle(Control c)
        {
            if (c.GetType().IsAssignableFrom(typeof(TreeList)))
            {
                XPathNodeIterator nodes = null;

                if (c.Tag != null && c.Tag.ToString().Trim().Length > 0)
                {
                    nodes = xNav.Select(XPath + "/" + c.Tag.ToString());
                }

                else
                {
                    nodes = xNav.Select(XPath + "/" + c.Name.Substring(3));
                }

                ((TreeList)c).BeginUpdate();
                ((TreeList)c).Nodes.Clear();

                String keyFiledName = "";
                String parentFieldName = "";
                foreach (TreeListColumn column in ((TreeList)c).Columns)
                {
                    if (column.FieldName.Equals(((TreeList)c).KeyFieldName))
                    {
                        keyFiledName = column.FieldName;
                    }
                    if (column.FieldName.Equals(((TreeList)c).ParentFieldName))
                    {
                        parentFieldName = column.FieldName;
                    }
                }

                TreeListNode parentNode = null;
                Object parentFieldValue = "";
                foreach (XPathNavigator node in nodes)
                {
                    ArrayList values = new ArrayList();

                    foreach (TreeListColumn column in ((TreeList)c).Columns)
                    {
                        XPathNavigator _node = null;

                        if (column.Tag != null && column.Tag.ToString().Trim().Length > 0)
                        {
                            _node = node.SelectSingleNode(column.Tag.ToString());
                        }

                        else
                        {
                            _node = node.SelectSingleNode(column.Name.Substring(3));
                        }

                        Object _Value = null;
                        if (_node == null)
                        {
                            _Value = null;
                        }
                        else
                        {
                            switch (column.UnboundType)
                            {
                                case DevExpress.XtraTreeList.Data.UnboundColumnType.Object:
                                    _Value = _node.Value;
                                    break;
                                case DevExpress.XtraTreeList.Data.UnboundColumnType.Integer:
                                    _Value = _node.ValueAsInt;
                                    break;
                                case DevExpress.XtraTreeList.Data.UnboundColumnType.Decimal:
                                    _Value = _node.ValueAsDouble;
                                    break;
                                case DevExpress.XtraTreeList.Data.UnboundColumnType.DateTime:
                                    _Value = _node.ValueAsDateTime;
                                    break;
                                case DevExpress.XtraTreeList.Data.UnboundColumnType.String:
                                    _Value = _node.Value;
                                    break;
                                case DevExpress.XtraTreeList.Data.UnboundColumnType.Boolean:
                                    String _s = _node.Value;
                                    if (String.IsNullOrEmpty(_s))
                                    {
                                        _Value = false;
                                    }
                                    else
                                    {
                                        _Value = _s.Equals("1")
                                            || _s.ToUpper().Equals("T")
                                            || _s.ToUpper().Equals("TRUE")
                                            || _s.ToUpper().Equals("Y")
                                            || _s.ToUpper().Equals("YES")
                                            ;
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                        if (column.FieldName.Equals(parentFieldName))
                        {
                            parentFieldValue = _Value;
                        }
                        values.Add(_Value);
                    }

                    if (!String.IsNullOrEmpty(keyFiledName) && !String.IsNullOrEmpty(parentFieldName))
                    {
                        parentNode = ((TreeList)c).FindNodeByFieldValue(keyFiledName, parentFieldValue);
                    }

                    ((TreeList)c).AppendNode(values.ToArray(), parentNode);
                }
                ((TreeList)c).EndUpdate();
            }

            else
            {

                if (c.Tag != null && c.Tag.ToString().Trim().Length > 0)
                {
                    XPathNavigator node = xNav.SelectSingleNode(XPath + "/" + c.Tag.ToString());

                    if (node != null)
                    {
                        c.Text = node.Value;
                    }
                }
            }
        }

    }


    public class EncodeControlIterator : IControlIterator
    {
        private String RootElement;
        private XmlDocument xDoc = null;
        private XPathNavigator xNav = null;
        private XPathNavigator xRoot = null;

        public EncodeControlIterator(String RootElement)
        {
            this.RootElement = RootElement;
            this.xDoc = new XmlDocument();
            this.xDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><Root></Root>");
            this.xRoot = xDoc.CreateNavigator().SelectSingleNode("/Root");
            this.xRoot.AppendChild(String.Format("<{0}/>", RootElement));
            this.xNav = xDoc.CreateNavigator().SelectSingleNode("/Root/" + RootElement);
        }

        public void handle(Control c)
        {

            if (c.GetType().IsAssignableFrom(typeof(TreeList)))
            {
                if (c.Tag != null && c.Tag.ToString().Trim().Length > 0)
                {
                    String[] paths = c.Tag.ToString().Trim().Split('/');

                    XPathNavigator _xNav = xNav;

                    for (int d = 0; d < paths.Length - 1; d++)
                    {
                        if (_xNav.SelectSingleNode(String.Format("{0}", paths[d])) == null)
                        {
                            _xNav.AppendChild(String.Format("<{0}/>", paths[d]));
                        }

                        _xNav = _xNav.SelectSingleNode(String.Format("{0}", paths[d]));
                    }

                    // nodes
                    for (int i = 0; i < ((TreeList)c).Nodes.Count; i++)
                    {
                        TreeListNode Node = ((TreeList)c).Nodes[i];

                        _xNav.AppendChild(String.Format("<{0}/>", paths[paths.Length - 1]));

                        XPathNavigator _xNavNode = _xNav.SelectSingleNode(String.Format("{0}[last()]", paths[paths.Length - 1]));

                        // columns
                        for (int j = 0; j < ((TreeList)c).Columns.Count; j++)
                        {
                            TreeListColumn Column = ((TreeList)c).Columns[j];

                            XPathNavigator _xNavColumn = _xNavNode;
                            if (Column.Tag != null && Column.Tag.ToString().Trim().Length > 0)
                            {

                                foreach (String path in Column.Tag.ToString().Trim().Split('/'))
                                {
                                    if (_xNavColumn.SelectSingleNode(path) == null)
                                    {
                                        _xNavColumn.AppendChild(String.Format("<{0}/>", path));
                                    }
                                    _xNavColumn = _xNavColumn.SelectSingleNode(path);
                                }

                                String text = Convert.ToString(Node[Column]);
                                if (!String.IsNullOrEmpty(text))
                                {
                                    _xNavColumn.SetValue(text);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if (c.Tag != null && c.Tag.ToString().Trim().Length > 0)
                {
                    Stack<XPathNavigator> NavStack = new Stack<XPathNavigator>();

                    NavStack.Push(xNav);

                    foreach (String path in c.Tag.ToString().Trim().Split('/'))
                    {
                        if (NavStack.Peek().SelectSingleNode(String.Format("{0}", path)) == null)
                        {
                            //MessageBox.Show(xDoc.OuterXml);
                            NavStack.Peek().AppendChild(String.Format("<{0}/>", path));
                            //MessageBox.Show(xDoc.OuterXml);
                        }
                        NavStack.Push(NavStack.Pop().SelectSingleNode(String.Format("{0}", path)));
                    }

                    String text = c.Text;
                    if (!String.IsNullOrEmpty(text))
                    {
                        NavStack.Pop().SetValue(text);
                    }
                }
            }

        }

        public String asXML()
        {
            return xDoc.OuterXml;
        }

    }



    public class XMLHelper
    {

        public static void BindingData(Control _Control, StringReader reader)
        {
            BindingData(_Control, reader, "/Root");
        }

        public static void BindingData(Control _Control, StringReader reader, String XPath)
        {
            XPathDocument xDoc = new XPathDocument(reader);
            XPathNavigator xNav = xDoc.CreateNavigator();
            IControlIterator i = new BindingControlIterator(xDoc, xNav, XPath);
            GetControls(_Control, i);

        }

        public static void BindingData(Control _Control, XmlReader reader)
        {
            BindingData(_Control, reader, "/Root");
        }

        public static void BindingData(Control _Control, XmlReader reader, String XPath)
        {
            XPathDocument xDoc = new XPathDocument(reader);
            XPathNavigator xNav = xDoc.CreateNavigator();
            IControlIterator i = new BindingControlIterator(xDoc, xNav, XPath);
            GetControls(_Control, i);

        }

        public static void GetControls(Control _Control, IControlIterator i)
        {
            Stack<Control> stk = new Stack<Control>();
            stk.Push(_Control);

            while (stk.Count > 0)
            {
                Control c = stk.Pop();

                i.handle(c);

                if (c.HasChildren)
                {

                    foreach (Control _c in c.Controls)
                    {
                        stk.Push(_c);
                    }
                }
            }
        }

        public static String encode(Control _Control, String RootElement)
        {
            EncodeControlIterator i = new EncodeControlIterator(RootElement);
            GetControls(_Control, i);

            return i.asXML();
        }

        public static bool ShowException(String xmlData, bool ifShow)
        {
            if (String.IsNullOrEmpty(xmlData))
            {
                MessageBox.Show("xmlData is null");
                return true;
            }

            XPathDocument _xDoc = new XPathDocument(new StringReader(xmlData));
            XPathNavigator _xNav = _xDoc.CreateNavigator();

            XPathNavigator errMsg = _xNav.SelectSingleNode("/Root/Exception/ErrorMessage");
            if (errMsg != null)
            {
                if (ifShow)
                {
                    MessageBox.Show(errMsg.Value);
                }
                return true;
            }

            return false;
        }

        public static String SetXml(String xmlData)
        {
            return "<?xml version=\"1.0\" encoding=\"utf-8\"?><Root>" + xmlData + "</Root>";
        }

        public static XPathNavigator CreateNavigator(String xmlData)
        {
            return CreateNavigator(new StringReader(xmlData));
        }

        public static XPathNavigator CreateNavigator(StringReader reader)
        {
            return new XPathDocument(reader).CreateNavigator();
        }

        public static XPathNavigator CreateNavigator(XmlReader reader)
        {
            return new XPathDocument(reader).CreateNavigator();
        }

        public static String SelectSingleValue(String xmlData, String xpath)
        {
            String v = String.Empty;
            try
            {
                XPathNavigator node = CreateNavigator(xmlData).SelectSingleNode(xpath);

                v = node == null ? String.Empty : node.Value;
            }
            catch (Exception e)
            {
                MessageBox.Show("err " + e.Message);
            }
            return v;
        }
    }
}
